package gao.xiaolei.service;

import gao.xiaolei.dao.TestDesignCheckDao;
import gao.xiaolei.dao.TestDesignDao;
import gao.xiaolei.dao.TestProjectDao;
import gao.xiaolei.dto.*;
import gao.xiaolei.entity.TestDesign;
import gao.xiaolei.entity.TestDesignCheck;
import gao.xiaolei.entity.TestProject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import gao.xiaolei.util.ServiceName;
import gao.xiaolei.util.UuidUtil;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;

import java.time.Clock;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

@Service("TestDesignCheckService")
public class TestDesignCheckService {

    @Resource(name = "TestDesignCheckDao")
    private TestDesignCheckDao testDesignCheckDao;

    @Resource(name = "TestDesignDao")
    private TestDesignDao testDesignDao;

    @Resource(name = "TestProjectDao")
    private TestProjectDao testProjectDao;

    @Autowired
    private RestTemplate restTemplate;

    @Resource(name = "TestDesignService")
    private TestDesignService testDesignService;

    @Resource(name = "AnalysisService")
    private AnalysisService analysisService;


    //添加审核记录
    @Transactional
    public void addCheck(List<TestCheckCreateDto> testRequirementChecks) {
        LocalDateTime checkDate = LocalDateTime.now(Clock.system(ZoneId.of("Asia/Shanghai")));
        for (TestCheckCreateDto dto : testRequirementChecks) {
            if (dto.getIsFinish() == 1) {
                testDesignDao.updateStatus(dto.getTargetId(), dto.getIsPass() == 1 ? 3 : -1);
                analysisService.doAnalysis(testDesignDao.getProject(dto.getTargetId()));//更新测试需求分析
            } else
                testDesignDao.updateStatus(dto.getTargetId(), 2);
            testDesignCheckDao.save(new TestDesignCheck(UuidUtil.get32Uuid(), dto.getTargetId(), dto.getCheckMan(), dto.getAnnotate(), dto.getIsPass(), dto.getIsFinish(), checkDate, getTestDesignSubjectPath(dto.getTargetId()), testDesignDao.getProject(dto.getTargetId())));
        }
    }


    //获取某个审核人的审核记录
    @Transactional(readOnly = true)
    public List<TestCheckDto> findByCheckManAndIsFinsh(String checkMan, Integer isFinish, String projectId) {
        List<TestDesignCheck> testDesignChecks = testDesignCheckDao.findByCheckManAndIsFinishAndProjectId(checkMan, isFinish, projectId);
        List<TestCheckDto> trcDtos = new ArrayList<>(testDesignChecks.size());
        for (int i = 0, length = testDesignChecks.size(); i < length; i++) {
            String targetName = Optional.ofNullable(testDesignDao.getTitle(testDesignChecks.get(i).getTargetId())).orElse("已删除");
            String result = testDesignChecks.get(i).getIsPass() == 1 ? "审核通过" : "审核未通过";
            trcDtos.add(new TestCheckDto(testDesignChecks.get(i).getId(), targetName, null, result, testDesignChecks.get(i).getCheckDate(), testDesignChecks.get(i).getSubjectPath()));
        }
        return trcDtos;
    }

    //获取待审核的测试计划
    @Transactional(readOnly = true)
    public List<TestCheckDto> getReadyToCheck(String projectId) {
        List<TestDesign> designs = testDesignDao.findByProjectAndStatus(projectId, 1);
        List<TestCheckDto> testCheckDtos = new ArrayList<>(designs.size());
        for (int i = 0, length = designs.size(); i < length; i++) {
            testCheckDtos.add(new TestCheckDto(null, designs.get(i).getTitle(), designs.get(i).getId(), null, null, getTestDesignSubjectPath(designs.get(i).getId())));
        }
        return testCheckDtos;
    }

    //获取某个测试计划的的所有审核记录,但只是返回id,isPass,checkMan,checkDate,isFinish
    @Transactional(readOnly = true)
    public List<TestCheckLogDto> getTargetCheckLog(String targetId) {
        List<TestDesignCheck> checkLogs = objToTestDesign5(testDesignCheckDao.findByTarget(targetId));
        List<TestCheckLogDto> dtos = new ArrayList<>(checkLogs.size());
        for (int i = 0, length = checkLogs.size(); i < length; i++) {
            String checkManName = restTemplate.getForObject(ServiceName.AUTH_SERVICE.getServiceName().concat("/user/realName/").concat(checkLogs.get(i).getCheckMan()), String.class);
            dtos.add(new TestCheckLogDto(checkLogs.get(i).getId(), checkManName, checkLogs.get(i).getIsPass(), checkLogs.get(i).getIsFinish(), checkLogs.get(i).getCheckDate()));
        }
        return dtos;
    }

    //获取审核的批注内容
    public String getAnnotate(String id) {
        return Optional.ofNullable(testDesignCheckDao.getAnnotate(id)).orElse("无");
    }

    //修改审核是否通过和审核批注
    @Transactional
    public void updateAnnotateAndIsPass(List<TestCheckCreateDto> chooseCheck) {//能修改说明本身已经存在审核，所以前端就只传了测试审核Id没有传targetId
        for (TestCheckCreateDto dto : chooseCheck) {
            testDesignCheckDao.updateAnnotateAndIsPass(dto.getAnnotate(), dto.getIsPass(), dto.getId());
            if (testDesignCheckDao.getIsFinish(dto.getId()) == 0 && dto.getIsFinish() == 1)
                testDesignCheckDao.updateIsFinish(dto.getIsFinish(), dto.getId());
            String targetId = testDesignCheckDao.getTarget(dto.getId());
            int count = testDesignCheckDao.getCountByTargetIdAndCheckDateAfter(targetId, testDesignCheckDao.getCheckDate(dto.getId()));
            if (count == 0) {//如果修改的审核是对这个测试计划最新的审核的话，就要去更改对应测试计划的状态
                int nowStatus = testDesignDao.getStatus(targetId);
                if ((nowStatus == 2 && dto.getIsFinish() == 1) || nowStatus == 3 || nowStatus == -1) {//如果测试计划本身处于审核中并且想完成审核||本身就是已经审核完成才能去修改自己的状态，目的是防止测试计划从审核完成的状态变回审核中的状态
                    testDesignDao.updateStatus(targetId, dto.getIsPass() == 1 ? 3 : -1);
                }
                analysisService.doAnalysis(testDesignDao.getProject(targetId));//更新测试需求的分析
            }
        }
    }

    //获取审核详情
    @Transactional(readOnly = true)
    public TestCheckDetailDto getDetail(String id, Integer status) {//如果是待审核的话，传过来的id就是指对应的测试计划Id
        String targetId = null;
        TestDesignCheck t = null;
        if (status != -1) {//如果不是在待审核界面查看
            t = testDesignCheckDao.findById(id).get();
            targetId = t.getTargetId();
        } else
            targetId = id;
        String targetName = Optional.ofNullable(testDesignDao.getTitle(targetId)).orElse("已删除");
        Integer isDeleted = 0;
        TestDesignOutDto testDesignOutDto = null;
        if ("已删除".equals(targetName)) //说明这个测试需求已经被删除了
            isDeleted = 1;
        else
            testDesignOutDto = testDesignService.getDetail(targetId);
        if (status != -1)//如果不是在待审核界面查看
            return new TestCheckDetailDto(id, targetId, targetName, t.getIsPass(), t.getAnnotate(), t.getCheckDate(), isDeleted, testDesignOutDto);
        else
            return new TestCheckDetailDto(null, targetId, targetName, 0, "", null, isDeleted, testDesignOutDto);
    }

    //用于将从数据库里查出来的List<Object[]>转换为List<TestDesignCheck>(id,isPass,checkMan,isFinish,checkDate)
    private List<TestDesignCheck> objToTestDesign5(List<Object[]> os) {
        List<TestDesignCheck> ts = new ArrayList<>(os.size());
        for (int i = 0, length = os.size(); i < length; i++) {
            ts.add(new TestDesignCheck((String) os.get(i)[0], (Integer) os.get(i)[1], (String) os.get(i)[2], (Integer) os.get(i)[3], (LocalDateTime) os.get(i)[4]));
        }
        return ts;
    }

    // 用于将从数据库里查出来的List<Object[]>转换为List<TestProject>(id,name)
    private List<TestProject> objToTestProject2(List<Object[]> os) {
        List<TestProject> ts = new ArrayList<>(os.size());
        for (int i = 0, length = os.size(); i < length; i++) {
            ts.add(new TestProject((String) os.get(i)[0], (String) os.get(i)[1]));
        }
        return ts;
    }

    //获取某一个测试计划的所属主题文件夹
    private String getTestDesignSubjectPath(String id) {
        List<String> path = new LinkedList<>();
        String parentId = testDesignDao.getParentId(id);
        while (!"root".equals(parentId) && parentId != null) {
            path.add(testDesignDao.getTitle(parentId));
            parentId = testDesignDao.getParentId(parentId);
        }
        StringBuilder result = new StringBuilder();
        for (int i = path.size() - 1; i >= 0; i--) {
            result.append(path.get(i)).append("/");
        }
        result.deleteCharAt(result.length() - 1);
        return result.toString();
    }
}
